package com.stox.repository.file;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.stox.dto.enumeration.SpanType;
import com.stox.manager.CountryManager;
import com.stox.manager.ExchangeManager;
import com.stox.manager.ScripManager;
import com.stox.model.Bar;
import com.stox.model.Country;
import com.stox.model.Exchange;
import com.stox.model.Scrip;
import com.stox.repository.BarRepository;
import com.stox.repository.file.iterator.StartAndCountAwareBarIterator;
import com.stox.repository.file.iterator.StartAndEndAwareBarIterator;

@Component
public class BarFileRepository extends AbstractFileRepository<Bar, Long> implements BarRepository, InitializingBean {
	
	@Autowired
	private ScripManager scripManager;
	
	@Autowired
	private ExchangeManager exchangeManager;
	
	@Autowired
	private CountryManager countryManager;
	
	public void afterPropertiesSet() throws Exception {
		for(Country country : countryManager.findAll()){
			for(Exchange exchange : exchangeManager.findByCountryId(country.getId())){
				for(Scrip scrip : scripManager.findByExchangeId(exchange.getId())){
					try {
						cache(getFilePath(scrip.getId()));
					}catch(FileNotFoundException e) {
						System.out.println("File not found for : "+scrip);
					}
				}
			}
		}
	}
	
	@Override
	protected String getFilePath(Long scripId) {
		Scrip scrip = scripManager.findOne(scripId);
		if(null == scrip) return null;
		Exchange exchange = exchangeManager.findOne(scrip.getExchangeId());
		if(null == exchange) return null;
		return getFilebasePath()+File.separator+
				exchange.getCountryId()+File.separator+exchange.getId()+File.separator+scrip.getId()+".csv";
	}
	
	@Override
	protected Bar deserialize(String text, Long scripId) {
		try{
			return new Bar(scripId, text);
		}catch(RuntimeException e){
			throw e;
		}
	}
	
	@Override
	public synchronized List<Bar> findByScripId(Long scripId, SpanType spanType, Date start,int count) {
		StartAndCountAwareBarIterator iterator = new StartAndCountAwareBarIterator(start, count);
		iterator.setSpanType(spanType);
		iterate(iterator, scripId);
		return iterator.getBars();
	}
	
	@Override
	public List<Bar> findByScripId(Long scripId, SpanType spanType, Date start,
			Date end) {
		StartAndEndAwareBarIterator iterator = new StartAndEndAwareBarIterator(start, end);
		iterator.setSpanType(spanType);
		iterate(iterator, scripId);
		return iterator.getBars();
	}
	
	public List<Bar> findByScripId(Long scripId){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar entity) {
				bars.add(entity);
				return true;
			}
		}, scripId);
		return bars;
	}

	public List<Bar> findByScripId(Long scripId, final Date start){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar bar) {
				bars.add(bar);
				return (bar.getDate().after(start) || bar.getDate().equals(start));
			}
		}, scripId);
		return bars;
	}
	
	public List<Bar> findByScripId(Long scripId,final int count){
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			private int subCount;
			public boolean shouldContinue(Bar bar) {
				bars.add(bar);
				return subCount <= count;
			}
		}, scripId);
		return bars;
	}
	
	public List<Bar> findByScripCode(Long scripId, final Date start, final Date end) {
		final List<Bar> bars = new ArrayList<Bar>();
		iterate(new EntityIterator<Bar>(){
			public boolean shouldContinue(Bar bar) {
				if((bar.getDate().equals(start) || bar.getDate().after(start)) &&
						(bar.getDate().equals(end) || bar.getDate().before(end))){
					bars.add(bar);
				}
				return bar.getDate().before(start);
			}
		}, scripId);
		return bars;
	}
	
	private int count;
	private void checkFlush(){
		count++;
		if(100000 <= count){
			flush();
			count = 0;
		}
	}
	
	public Bar save(Bar bar) {
		checkFlush();
		return super.save(bar, bar.getScripId());
	}

	@Override
	protected String serialize(Bar bar) {
		return bar.toString();
	}

}
